#!/usr/bin/env python
# -*- coding: utf-8 -*-
from xml.etree.ElementTree import ElementTree
from StringIO import StringIO #cStringIO ne prend pas utf-8
import re
import uuid

#Auto
#TODO revoir emplacement
class Extend:
    def __init__(self,xmlfile):
        self._tree=ElementTree(None,xmlfile)
        self._root=self._tree.getroot()
        self._sourceFileNames=[]
        self._styles={}
        self._keywords={}
        self._types={}
        self._value={}
        self._defaultStyles={}
        self._read()
        
    
    def getTemplates(self):
        return []
    
    def isReady(self):
        return True
    
    def start(self):
        pass
    
    def stop(self):
        pass
        
        
    def close(self):
        pass
    
    def _read(self):
        self._rules=self._tree.getroot().findall('rules/rule')
        filenames=self._tree.getroot().findall('head/source/filename')
        for filename in filenames:
            self._sourceFileNames.append(filename.text)
        styles=self._tree.getroot().findall('styles/style')
        for style in styles:
            self._styles[int(style.attrib['id'])]=style.text
        
        keywords=self._tree.getroot().findall('keywords/keyword')
        for word in keywords:
            self.addType(word.attrib['type'] , word.text.split(' '))
            self._keywords[int(word.attrib['id'])]=self._types[word.attrib['type']]
            
    
   
    def addType(self,name,value):
        if not self._types.has_key(name):
            self._types[name]=[]
        if type(value)==list:
            self._types[name]=self._types[name]+value
        else:
            self._types[name].append(value)
    
    def getType(self,name):
        return self._types[name]

    def getLexer(self):
        return int(self._tree.getroot().find('head/lexer').text)
        
    def getStyles(self):
        return self._styles
    
    def getKeyWord(self):
        return self._keywords
    
    def getSourceFileNames(self):
        return self._sourceFileNames
    
    def read(self,text,id=None):
        self.cr=CodeReader2(self._rules,self)
        self.cr.read(text)
        return;

    def getRootContext(self):
        return self.cr.root
    
    def getCompletion(self,cursorPos,text=None):
        return self.cr.getCompletion(text, cursorPos)
    
    def getContextObject(self,name):
        return self.cr.getContextObject()



class CodeReader2:
    def __init__(self,rules,lang):
        self._rules=rules
        self._lang=lang
        
        self._level=0
        self._prev=None
        self.root=None
        self._contexts={}
        
    def read(self,text,cursorPosition=0,cursorLine=0):
        #text=text.replace(';',";\n");
        self._text=text
        strIO=StringIO(text)
        strIO.seek(0)
        while 1:
            try:
                line= strIO.next()
            except:
                break
            
            self._readLine(line)
            
        return []#completion
    
    def _readLine(self,line,cursorPosition=0):
        if line.find("{")>=0:
            self._level+=1
        if line.find("}")>=0:
            self._level-=1
        #self.currentLine=LineReader(self._rules)   
        #ret=[]
        for rule in self._rules:
            exp=rule.findtext('exp')
            if exp is not None:
                #if cursorPosition:
                #    result=re.search(exp,repr(line[0:cursorPosition]))
                #    if result:
                #        self._createContextRule(rule,result).
                result=re.search(exp,repr(line))
                if result:
                    self._createContextRule(rule,result)
                    break
        #if context and context.typeValue and:
            
        
        #return ret        
    
    def getCompletion(self,text,cursorPos):
        ret=[]
        for rule in self._rules:
            str=rule.find('str')
            if str is not None:
                completionRules=rule.findall('completion')
                for completionRule in completionRules:
                    index=int(completionRule.attrib['index'])
                    if text[cursorPos+index]==str.text:
                        if completionRule.attrib.has_key('type'):
                            ret+=self._lang.getType(completionRule.attrib['type'])
                        if completionRule.text:
                            ret+=completionRule.text.split(' ')
                        break;
            str=rule.find('exp')
            #if str.attrib.has_key('pos'): 
            #    pos=int(str.attrib['pos'])
            
        return ret

    
    def _createContextRule(self,rule,result):
        contextsRules=rule.findall('context')
        lineContext=[]
        for contextRule in contextsRules:
            name="patate"
            if contextRule.attrib.has_key('name'): 
                name=contextRule.attrib['name']
            elif contextRule.attrib.has_key('index'):
                name=result.group(int(contextRule.attrib['index']))
            
            context=self._getContext(name)
            context.ruleName=rule.attrib['name']
            lineContext.append(context)
            
            if contextRule.attrib.has_key('type'):
                self._lang.addType(contextRule.attrib['type'],name)
                
            self._readAttrRule(context,contextRule,result,lineContext)
            groups=contextRule.findall('group')
            for groupRule in groups:
                self._readAttrRule(context,groupRule,result,lineContext)
            
            if contextRule.attrib.has_key('haveChild') and contextRule.attrib['haveChild']=='true':
                self._prev=context
        return context
            #data.id=uuid.uuid1().get_hex()
    
    def _readAttrRule(self,context,rule,result,lineContext):
        if rule.attrib.has_key('index'):
            g=int(rule.attrib['index'])
        for attr in rule.attrib:
            value=rule.attrib[attr]
            if attr!='name' and attr!='index':
                #print (attr ,value,value[0:9])
                if value[0]=='$':
                    if value[0:10]=='${context(':                   
                        value=lineContext[int(value[10:value.find(')')])]
                    else:
                        value=value.replace('${context}',context.name)
                        value=value.replace('${self}',result.group(g))
            if attr=='parent':
                if context.parent:
                    context.parent.removeChild(context.name)
                value.addChild(context)
            else:
                setattr(context,attr,value)

    def _getContext(self,name,parent=None):
        if parent and self.getContextObject(parent):
            if self.getContextObject(parent).getChild(name):
                return self.getChild(name)
            else:
                return self._createContext(name,parent)
        elif self.getContextObject(name):
            return self.getContextObject(name)
        else:
            return self._createContext(name,parent)

    def _getCurrentParent(self):
        if not self._prev:
            return None
        elif self._level>self._prev.level:
            return self._prev
        elif self._level==self._prev.level and self._prev.parent:
            return self._prev.parent
 
    def _createContext(self,name,parent=None):
        context=ContextObject()
        context.level=self._level
        context.name=name
        
        if parent and  self._getContext(parent):
            self._getContext(parent).addChild(context)
        elif not self._prev:
            self.root=context
        else:
            self._getCurrentParent().addChild(context)
        #elif context.level==self.prev.level and self.prev.parent:
        #    self.prev.parent.addChild(context)
        return context


    def _getCurrentPath(self,name):
        parent=self._getCurrentParent()
        if parent:
            return parent.path+'/'+name
        else:
            return'/'+name


    def getContextObject(self,name):
        if self._contexts.has_key(name):
            return self._contexts[name]
        else:
            return None

class LineReader():
    def __init__(self,value,rule,result):
        self.value=value
        self.rule=rule
        self.result=result
        self.contexts=[]
        self._readRule()
    
      
    def _readRule(self):
        contextsRules=self.rule.findall('context')
        for contextRule in contextsRules:
            data={}
            name="patate"
            if contextRule.attrib.has_key('name'): 
                name=contextRule.attrib['name']
            elif contextRule.attrib.has_key('group'):
                name=self.result.group(int(contextRule.attrib['group']))
            
            context=self._getContext(name)
            self.contexts.append(context)
            if contextRule.attrib.has_key('type'):
                self._lang.addType(contextRule.attrib['type'],name)
                
                
            
            if contextRule.attrib.has_key('haveChild') and contextRule.attrib['haveChild']=='true':
                self._prev=context
            
            #data.id=uuid.uuid1().get_hex()

class CodeReader:
    
    def __init__(self,rules,lang):
        self._rules=rules
        self._lang=lang
        
        self._level=0
        self.prev=None
        self.root=None
        self._contexts={}
        
    def read(self,text):
        self._text=text
        strIO=StringIO(text)
        strIO.seek(0)
        cpt=0
        while 1:
            
            try:
                line= strIO.next()
            except:
                break
            
            self._readLine(line,cpt)
            cpt+=1
    
    def _readLine(self,line,number=-1):
        if line.find("{")>=0:
            self._level+=1
        if line.find("}")>=0:
            self._level-=1
        for rule in self._rules:
            #try:
                exp=rule.find('exp').text
                result=re.search(exp,repr(line))
                if result:
                    self._readRule(rule,result)
                    break
            #except:
            #    pass
    
      
    def _readRule(self,rule,result):
        childs=rule.findall('group')
        
        context=None
        for child in childs:
            g=int(child.attrib['index'])
            
            if child.attrib.has_key("name"):
                name=self._replaceTag(child.attrib["name"],child,result)
                if child.attrib.has_key("parent"):
                    context=self._getContext(name,self._replaceTag(child.attrib["parent"],child,result))
                else:
                    context=self._getContext(name)
                
            
            for attr in child.attrib:
                if attr != 'index' and attr != 'parent' and attr != 'name':
                    #print ('setattr',attr)
                    setattr(context,attr,self._replaceTag(child.attrib[attr],child,result))
                if attr=='type':
                    self._lang.addType(child.attrib['type'],result.group(g))
                    
            if context.type:
                self.prev=context
                
            if context.parent:
                #print ('parent',context.parent)
                context.path=context.parent.path
            context.path+='/'+context.name
            self._contexts[context.path]=context
            
            context.ruleName=rule.attrib['name']


    def _getContext(self,name,parent=None):
        if parent and self.getContextObject(parent):
            if self.getContextObject(parent).getChild(name):
                return self.getChild(name)
            else:
                return self._createContext(name,parent)
        elif self.getContextObject(name):
            return self.getContextObject(name)
        else:
            return self._createContext(name,parent)

    def _getCurrentParent(self):
        if not self.prev:
            return None
        elif self._level>self.prev.level:
            return self.prev
        elif self._level==self.prev.level and self.prev.parent:
            return self.prev.parent
 
    def _createContext(self,name,parent=None):
        context=ContextObject()
        context.level=self._level
        context.name=name
        
        if parent and  self._getContext(parent):
            self._getContext(parent).addChild(context)
        elif not self.prev:
            self.root=context
        else:
            self._getCurrentParent().addChild(context)
        #elif context.level==self.prev.level and self.prev.parent:
        #    self.prev.parent.addChild(context)
        return context


    def _getCurrentPath(self,name):
        parent=self._getCurrentParent()
        if parent:
            return parent.path+'/'+name
        else:
            return'/'+name

    def _replaceTag(self,value,tag,expresult):
        g=int(tag.attrib['index'])
        value=value.replace("${self}",expresult.group(g))
        value=value.replace("${element}",self._getCurrentPath(expresult.group(g)))
        return value


    def getContextObject(self,name):
        if self._contexts.has_key(name):
            return self._contexts[name]
        else:
            return None

        
class ContextObject(object):
    def __init__(self):
        self.level=0
        self.name=""
        self.ruleName=""
        self.type=None
        self.childs={}
        self.parent=None
        self.typeValue=None
        self.path=""
        self.id=""
        #self.modifer
    
    def getStringTypeValue(self):
        if self.typeValue:
            return self.typeValue
        else:
            return "None"
    
    def read(self,tag,expResult):
        pass
    
    def addChild(self,child):
        self.childs[child.name]=child
        child.parent=self
        
    def getChilds(self):
        return self.childs.values()
    
    def getChild(self,name):
        if self.childs.has_key(name):
            return self.childs[name]
        else:
            return None
        
    def removeChild(self,name):
        del self.childs[name]
        
        
        
        